#ifndef SCENE_HPP
#define SCENE_HPP

#include <string>
#include <vector>
#include <typeinfo>


class Scene {
public:
    virtual ~Scene() {}

    static Scene* Factory();

public:
    struct ShadowDescriptor {
        
    };

    struct TypeDescriptor {
        std::string name;
        int size;
        void (*constructor)(void *ptr);
        void (*destructor)(void *object);
        std::vector<ShadowDescriptor> shadows;
    };

    static void RegisterType(const TypeDescriptor &descriptor);

    template <typename T>
    static void RegisterType(TypeDescriptor &descriptor) {
        descriptor.name = typeid(T).name();
        RegisterType(descriptor);
    }

    template <typename T>
    static void SimpleConstructor(void *ptr) {
        new (ptr) T;
    }

    template <typename T>
    static void SimpleDestructor(void *object) {
        static_cast<T*>(object)->~T();
    }

    template <typename T>
    static void RegisterSimpleType() {
        Scene::TypeDescriptor d;
        d.size = sizeof(T);
        d.constructor = SimpleConstructor<T>;
        d.destructor = SimpleDestructor<T>;
        RegisterType<T>(d);
    }

private:
    virtual void* AllocateBase(const std::type_info &t) = 0;

    virtual void* DestroyBase(const std::type_info &t, void *object) = 0;

public:
    template <typename T>
    T* Allocate() {
        T* object = static_cast<T*>(AllocateBase(typeid(T)));
        if (object == NULL) {
            return new T;
        }
        return object;
    }

    template <typename T>
    void Destroy(T *object) {
        T* remain = static_cast<T*>(DestroyBase(typeid(T), object));
        if (remain != NULL) {
            delete remain;
        }
    }
};
#endif
